using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using log4net;
using Microsoft.CSharp;
using Triton.Common.LogUtilities;

namespace Triton.Common
{
	public class CodeCompiler
	{
		public enum FileStructureType
		{
			SingleFile,
			Folder
		}

		[CompilerGenerated]
		private sealed class Class230
		{
			public string string_0;

			internal bool method_0(Assembly assembly_0)
			{
				return assembly_0.GetName().Name.Contains(string_0.Replace(".dll", string.Empty));
			}
		}

		private static readonly ILog ilog_0;

		private static string string_0;

		private static string string_1;

		[CompilerGenerated]
		private Assembly assembly_0;

		[CompilerGenerated]
		private string string_2;

		[CompilerGenerated]
		private FileStructureType fileStructureType_0;

		[CompilerGenerated]
		private CompilerParameters compilerParameters_0;

		[CompilerGenerated]
		private float float_0;

		[CompilerGenerated]
		private string string_3;

		[CompilerGenerated]
		private List<string> list_0;

		private readonly List<string> list_1 = new List<string>();

		private readonly List<Stream> list_2 = new List<Stream>();

		private ResourceWriter resourceWriter_0;

		public static string CompiledAssemblyPath => string_1 ?? (string_1 = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), $"CompiledAssemblies\\{Environment.TickCount}"));

		public Assembly CompiledAssembly
		{
			[CompilerGenerated]
			get
			{
				return assembly_0;
			}
			[CompilerGenerated]
			private set
			{
				assembly_0 = value;
			}
		}

		public string SourcePath
		{
			[CompilerGenerated]
			get
			{
				return string_2;
			}
			[CompilerGenerated]
			private set
			{
				string_2 = value;
			}
		}

		public FileStructureType FileStructure
		{
			[CompilerGenerated]
			get
			{
				return fileStructureType_0;
			}
			[CompilerGenerated]
			private set
			{
				fileStructureType_0 = value;
			}
		}

		public CompilerParameters Options
		{
			[CompilerGenerated]
			get
			{
				return compilerParameters_0;
			}
			[CompilerGenerated]
			private set
			{
				compilerParameters_0 = value;
			}
		}

		public float CompilerVersion
		{
			[CompilerGenerated]
			get
			{
				return float_0;
			}
			[CompilerGenerated]
			private set
			{
				float_0 = value;
			}
		}

		public string AssemblyName => $"{((FileStructure == FileStructureType.SingleFile) ? Path.GetFileNameWithoutExtension(SourcePath) : new DirectoryInfo(SourcePath).Name)}.dll";

		public string CompiledToLocation
		{
			[CompilerGenerated]
			get
			{
				return string_3;
			}
			[CompilerGenerated]
			private set
			{
				string_3 = value;
			}
		}

		public List<string> SourceFilePaths
		{
			[CompilerGenerated]
			get
			{
				return list_0;
			}
			[CompilerGenerated]
			private set
			{
				list_0 = value;
			}
		}

		internal static void SetString_0(string string_4)
		{
			string_0 = string_4;
		}

		private static void smethod_1()
		{
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CompiledAssemblies");
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
			foreach (string path2 in files)
			{
				try
				{
					File.Delete(path2);
				}
				catch (Exception)
				{
				}
			}
			files = Directory.GetDirectories(path);
			foreach (string path3 in files)
			{
				try
				{
					Directory.Delete(path3);
				}
				catch (Exception)
				{
				}
			}
			if (!Directory.Exists(CompiledAssemblyPath))
			{
				Directory.CreateDirectory(CompiledAssemblyPath);
			}
		}

		static CodeCompiler()
		{
			ilog_0 = Logger.GetLoggerInstanceForType();
			smethod_1();
		}

		public CodeCompiler(string path)
		{
			CompilerVersion = 4f;
			SourceFilePaths = new List<string>();
			if (File.Exists(path))
			{
				FileStructure = FileStructureType.SingleFile;
			}
			else if (Directory.Exists(path))
			{
				FileStructure = FileStructureType.Folder;
			}
			SourcePath = path;
			Options = new CompilerParameters
			{
				GenerateExecutable = false,
				GenerateInMemory = false,
				IncludeDebugInformation = true
			};
			string arg = "HSB_" + Assembly.GetEntryAssembly().GetName().Version.Revision;
			Options.CompilerOptions = $"/d:HSB;{arg} /unsafe";
			Options.TempFiles = new TempFileCollection(Path.GetTempPath());
			Options.OutputAssembly = Path.Combine(CompiledAssemblyPath, AssemblyName);
			CompiledToLocation = Options.OutputAssembly;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					string location = assembly.Location;
					if (assembly == Assembly.GetEntryAssembly())
					{
						location = string_0;
					}
					AddReference(location);
				}
				catch (NotSupportedException)
				{
				}
			}
		}

		public void AddReference(string assembly)
		{
			if (!Options.ReferencedAssemblies.Contains(assembly))
			{
				Options.ReferencedAssemblies.Add(assembly);
			}
		}

		private void method_0(string string_4)
		{
			if (resourceWriter_0 == null)
			{
				string text = Path.GetFileNameWithoutExtension(AssemblyName) + ".g.resources";
				resourceWriter_0 = new ResourceWriter(text);
				Options.EmbeddedResources.Add(text);
				list_1.Add(text);
			}
			FileStream fileStream = new FileStream(string_4, FileMode.Open, FileAccess.Read);
			list_2.Add(fileStream);
			resourceWriter_0.AddResource(Path.GetFileName(string_4).ToLowerInvariant(), fileStream);
		}

		private void method_1(string string_4)
		{
			string text = Path.ChangeExtension(string_4, ".resources");
			if (File.Exists(text))
			{
				File.Delete(text);
			}
			using (ResXResourceReader resXResourceReader = new ResXResourceReader(string_4))
			{
				resXResourceReader.BasePath = SourcePath;
				using ResourceWriter resourceWriter = new ResourceWriter(text);
				foreach (DictionaryEntry item in resXResourceReader)
				{
					resourceWriter.AddResource(item.Key.ToString(), item.Value);
				}
			}
			Options.EmbeddedResources.Add(text);
		}

		private void method_2()
		{
			if (FileStructure == FileStructureType.Folder)
			{
				string[] files = Directory.GetFiles(SourcePath, "*.resx", SearchOption.AllDirectories);
				foreach (string string_ in files)
				{
					method_1(string_);
				}
				bool flag = false;
				files = Directory.GetFiles(SourcePath, "*.baml", SearchOption.AllDirectories);
				foreach (string string_2 in files)
				{
					flag = true;
					method_0(string_2);
				}
				files = Directory.GetFiles(SourcePath, "*.cs", SearchOption.AllDirectories);
				foreach (string text in files)
				{
					if (text.ToLowerInvariant().Contains(".g.cs"))
					{
						if (flag)
						{
							SourceFilePaths.Add(text);
						}
					}
					else if (text.ToLowerInvariant().Contains(".xaml.cs"))
					{
						if (flag)
						{
							SourceFilePaths.Add(text);
						}
					}
					else
					{
						SourceFilePaths.Add(text);
					}
				}
			}
			else
			{
				SourceFilePaths.Add(SourcePath);
			}
		}

		private static bool smethod_2(string string_4)
		{
			return AppDomain.CurrentDomain.GetAssemblies().Any((Assembly assembly_0) => assembly_0.GetName().Name.Contains(string_4.Replace(".dll", string.Empty)));
		}

		private void method_3()
		{
			foreach (string sourceFilePath in SourceFilePaths)
			{
				string[] array = File.ReadAllLines(sourceFilePath);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (!text.StartsWith("//!CompilerOption|"))
					{
						continue;
					}
					string[] array2 = text.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
					switch (array2[1])
					{
					case "Define":
						if (array2.Length == 3 && !string.IsNullOrEmpty(array2[2]))
						{
							CompilerParameters options = Options;
							options.CompilerOptions = options.CompilerOptions + " /d:" + array2[2] + ";";
						}
						break;
					case "Optimize":
						if (array2.Length == 3 && !string.IsNullOrEmpty(array2[2]) && array2[2] == "On" && !Options.CompilerOptions.Contains("/optimize;"))
						{
							Options.IncludeDebugInformation = false;
							Options.CompilerOptions += " /optimize";
						}
						break;
					case "AddRef":
						if (array2.Length == 3 && !string.IsNullOrEmpty(array2[2]) && array2[2].EndsWith(".dll") && !smethod_2(array2[2]) && !array2[2].ToLowerInvariant().Contains("hearthbuddy.exe"))
						{
							AddReference(array2[2]);
						}
						break;
					}
				}
			}
		}

		public CompilerResults Compile()
		{
			method_2();
			method_3();
			if (SourceFilePaths.Count != 0)
			{
				using (CSharpCodeProvider cSharpCodeProvider = new CSharpCodeProvider(new Dictionary<string, string> { 
				{
					"CompilerVersion",
					string.Format(CultureInfo.InvariantCulture.NumberFormat, "v{0:N1}", CompilerVersion)
				} }))
				{
					cSharpCodeProvider.Supports(GeneratorSupport.Resources);
					if (resourceWriter_0 != null)
					{
						resourceWriter_0.Close();
						resourceWriter_0.Dispose();
						resourceWriter_0 = null;
					}
					foreach (Stream item in list_2)
					{
						try
						{
							item.Close();
							item.Dispose();
						}
						catch
						{
						}
					}
					list_2.Clear();
					CompilerResults compilerResults = cSharpCodeProvider.CompileAssemblyFromFile(Options, SourceFilePaths.ToArray());
					if (!compilerResults.Errors.HasErrors)
					{
						CompiledAssembly = compilerResults.CompiledAssembly;
					}
					compilerResults.TempFiles.Delete();
					foreach (string item2 in list_1)
					{
						try
						{
							File.Delete(item2);
						}
						catch
						{
						}
					}
					list_1.Clear();
					return compilerResults;
				}
			}
			if (resourceWriter_0 != null)
			{
				resourceWriter_0.Close();
				resourceWriter_0.Dispose();
				resourceWriter_0 = null;
			}
			foreach (Stream item3 in list_2)
			{
				try
				{
					item3.Close();
					item3.Dispose();
				}
				catch
				{
				}
			}
			list_2.Clear();
			foreach (string item4 in list_1)
			{
				try
				{
					File.Delete(item4);
				}
				catch
				{
				}
			}
			list_1.Clear();
			return null;
		}
	}
}
